<!--
 * @Author: ChengNan 1429323234@qq.com
 * @Date: 2024-08-05 15:32:06
 * @LastEditors: ChengNan 1429323234@qq.com
 * @LastEditTime: 2024-08-09 14:45:11
 * @FilePath: /src/views/10.virtualSelect/virtualSelect.vue
 * @Description: 虚拟列表 + select 实现
-->
<template>
  <div>
    <Select style="width: 200px;" v-model="txwkqMetricId" ref="inputW" class="inputW" filterable clearable 
    @on-query-change="queryChange"
    @on-open-change="openChange"
    :remote-method="remoteMethod1"
    @on-select="selectTxwkqMetricId">
      <VirtualListScroll
      class="VirtualListScroll"
      :extra-props="{ 'selectId': txwkqMetricId }"
      :keeps="20"
      :data-key="'id'"
      :data-sources="list2"
      :data-component="ItemComponent"/>
      <Option v-show="false" :value="gettxwkqMetricId.id">{{ gettxwkqMetricId.name}}</Option>
  </Select>
  </div>
</template>

<script>
import VirtualListScroll from "vue-virtual-scroll-list"
import ItemComp from './ItemComp';
import isa from './isa'; // 中间件
export default {
  components: {
    VirtualListScroll,
  },
  data() {
    return {
      ItemComponent: ItemComp, // option组件
      txwkqMetricId: '0', // 选中id
      searchQuery: '', // 查询条件
      list: Array.from({ length: 100 }, (_, i) => ({name: `Item ${i}`, id: '' + i})), // data数组
    }
  },
  computed: {
    gettxwkqMetricId() {
      // 过滤条件
      let find = this.list.find(el => el.id == this.txwkqMetricId) || {}
      this.selectTxwkqMetricId({value: find.id})
      return {
        id: find.id || '',
        name: find.name || '',
      }
    },
    list2() {
      // 过滤搜索数据
      if (this.searchQuery) {
        return this.list.filter(item => item.name.includes(this.searchQuery))
      } else {
        return this.list
      }
    },
  },
  mounted () {
    // 理念 采用虚拟列表 + select 的方式，实现加载万条数据的option，解决select卡顿问题
    // select 中加入 virtual 组件时，原有的下啦选项会渲染失效，需要手动，需要采用 virtual 的 comp 组件格式
    // 在使用该格式后，会发现选中数据并咩有样式，需要在 option 中手动书写新样式来补充 virtual 组件的缺失
    // 在 option 组件中 采用一个中间件来接受选中的数据，实现选中高亮，同时在 select 中写 一个 v-show = false 的 option 来保持 data 状态同步
    // 采用中间的原因是因为 数据存在渲染顺序，使用中间件 + watch 的方式来保持当前选择的数据是正确
    // 因为在选择的时候总是先出发选中数据的中间件，在调用 select 中的 option，在 watch 里面通过 isa 设置txwkqMetricId 来保持 data 状态同步

    // 重写验证函数，validateOption 是源码中的对搜索的校验，需要更改，如果不更改无法渲然option
    this.$refs.inputW.validateOption = () => true
    this.txwkqMetricId = '0'
  },
  methods: {
    // 选中
    selectTxwkqMetricId(value) {
      this.txwkqMetricId = ''
      isa.set('_selectId', value.value)
      this.txwkqMetricId = value.value
    },
    // 搜索
    queryChange(query) {
      if (!query) {
        this.searchQuery = ''
      }
    },
    // 手写远程搜索的方法
    remoteMethod1(query) {
      this.searchQuery = query
    },
    openChange(open) {
      console.log(open);
      if (open) {
        this.remoteMethod1(this.$refs.inputW.query)
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.VirtualListScroll {
  max-height: 190px;
  overflow-y: auto;
}
</style>